#include "syscall_types.h" //SYS_type
#include "trap.h" // tf
#include "stdio.h" // stdout
#include "sbi.h" // console_putchar(), shutdown()
#include "proc.h" // proc_switch()
#include "fs.h"

static ssize_t sys_read(int fd, void *buf, size_t count) {
	int i;
	char *p = (char *)buf;
	if (fd == stdin) {
		for (i = 0; i < count; ++i) {
			*p = console_getchar();
			p++;
		}
		return count;
	}
	return fs_read(fd, buf, count);
}

/* @brief: write data to file
 * @param fd: file descriptor
 * @param buf: data buffer
 * @param count: total number of data
 * @return: successfully written byte number, -1 if failed
 * @bug: can only write to screen now
 */
static ssize_t sys_write(int fd, const void *buf, size_t count) {
	int i;
	char *p = (char *)buf;
	// write to the screen
	if (fd == stdout || fd == stderr) {
		for (i = 0; i < count; ++i) {
			console_putchar(*p);
			p++;
		}
		return count;
	}
	// can't write to the file now
	return 0;
}

/* @brief: syscall dispatcher
 */
void syscall(struct trapframe *tf_ptr) {
	// syscall type store in a7
	uint64 type = tf_ptr->a7;
	uint64 ret = 0;
	uint64 args[6] = {tf_ptr->a0, tf_ptr->a1, tf_ptr->a2, tf_ptr->a3, tf_ptr->a4, tf_ptr->a5};
	switch (type) {
		case SYS_openat:
			ret = fs_openat(args[0], (char *)args[1], args[2], args[3]);
			break;
		case SYS_close:
			ret = fs_close(args[0]);
			break;
		case SYS_read:
			ret = sys_read(args[0], (void *)args[1], args[2]);
			break;
		case SYS_write:
			ret = sys_write(args[0], (void *)args[1], args[2]);
			break;
		case SYS_exit:
			proc_exit(args[0]);
			break;
		case SYS_getpid:
			ret = cur_proc->pid;
			break;
		case SYS_getppid:
			ret = cur_proc->parent_ptr->pid;
			break;
		case SYS_clone:
			ret = proc_clone(args[0], args[1], args[2], args[3], args[4]);
			break;
		case SYS_execve:
			ret = proc_execve((char *)args[0], (char **)args[1], (char **)args[2]);
			break;
		case SYS_wait4:
			ret = proc_wait(args[0], (int *)args[1], args[2]);
			break;
	}
	// stores return value of syscall
	tf_ptr->a0 = ret;
}
